Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compile static while #1431

Merged
merged 16 commits into from
May 15, 2023
Merged

Compile static while #1431

merged 16 commits into from
May 15, 2023

Conversation

paili0628
Copy link
Contributor

@paili0628 paili0628 commented May 1, 2023

if while body is static, then we want to make sure that the while body does not take the extra cycle incurred by the done condition. So we replace the while loop with enable of a wrapper group that sets the go signal of the static group in the while loop body high(all static control should be compiled into static groups by static_inliner now). The done signal of the wrapper group should be the condition that the fsm of the while body is %0 and the port signal is 1'd0.
For example, we replace

 wires {
 static group A<1> {
     ...
   }
   ...
 }
  
control {
   while l.out {
     A;
   }
 }

with

 wires {
   group early_reset_A {
    ...    
      }

   group while_wrapper_early_reset_A {
      early_reset_A[go] = 1'd1;
       while_wrapper_early_reset_A[done] = !l.out & fsm.out == 1'd0 ? 1'd1;
     }  
   }
 control {
     while_wrapper_early_reset_A;
  }

@paili0628 paili0628 requested a review from calebmkim May 1, 2023 03:59
@rachitnigam
Copy link
Contributor

Looking great @paili0628! @andrewb1999 will be extra happy about this one :-)

The done signal of the wrapper group should be the condition that the fsm of the while body is %0 and the port signal is 1'd0.

What is the intuition for why the fsm's state will be zero and the port signal be zero in the same cycle? Said differently, can we ever reach a case when the signal from the port is zero but the FSM has not reset yet. Does this case not matter?

For example, consider the following pseudo loop:

while i < 10 {
  i++;
  <do something>
}

In this case, we're incrementing the index variable in the first cycle of the loop body but then doing something else before exiting the loop. In this case, the conditional will be zero before the FSM is 0. However, that seems fine here because eventually the fsm will also become zero and hence the loop will exit. Is this always going to be true?

Also, can you test this out with doubly nested loops so make sure things are composing correctly?

calyx-opt/src/passes/compile_static.rs Outdated Show resolved Hide resolved
// control {
// while_wrapper_early_reset_A;
// }
if s.cond.is_none() {
Copy link
Contributor

@calebmkim calebmkim May 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't have to go in this PR, but I was thinking that we could probably support comb groups in this case as well (I was also thinking for supporting static if comb groups). I may be missing something, but it seems like all we would have to do is trigger the comb group assignments at cycle 0 (in this case add an fsm.out == 0 guard to each of the comb group assignments, and then inline them into the wrapper group). The comb assignments will be "done instantaneously" so the port will be updated to reflect the comb group assignments at cycle 0, which is what we want?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would be careful about with construct (see #927). Here is a particular case I ran into the last time I tried to handle if-with without creating extra groups out of it: #911 (comment)

The tried and true way to see if your reasoning about if-with lowering being correct is trying to make it work with the polybench integration tests.

@paili0628
Copy link
Contributor Author

paili0628 commented May 1, 2023

@rachitnigam I think this change only works if a Control::Static(_) is wrapped inside a while because we need to pull out the fsm for the loop body and check the port at %0. As a result, it cannot handle nested while loops (since inside the outer while loop will be a Control::While(_) which does not have a timer fsm. Yeah I'm not sure what to do with nested loops. Wondering if @calebmkim has an idea.

@calebmkim
Copy link
Contributor

Yeah I'm now realizing that this doesn't really work for nested loops sadly.
One thing I was thinking about is, what should happen in the following case:

while port1 {
    while port2 {
        static_body;
    }
} 

What if, when static_body's fsm resets back to 0, what if port2 is false but port1 is true? Should we just wait a cycle and not do anything, and then check port1 and port2 the next cycle?

@rachitnigam
Copy link
Contributor

@paili0628 Yup, I know. Just want to make sure that compilation correctly composes the nested group correctly.

@calebmkim This is not as bad as it looks because if two loops are directly nested in this manner, there is no computation being done between the end of the inner loops body and the check for the outer loops body. This means that we can collapse the nested loop into one loop:

while c1 {
  while c2 {
     body
  }
}

into:

while (!c2 && c1) | c2 {
  body 
}

Not sure if the collapsed loop's condition is correct or it should be c1 | c2 but you get the idea right?

@paili0628 paili0628 merged commit c46e4d9 into master May 15, 2023
@paili0628 paili0628 deleted the compile-static-while branch May 15, 2023 21:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants